<script lang="jsx">
import { FormItem } from 'ant-design-vue';
import { get, set } from 'lodash';

export default {
  props: {
    field: {
      type: Object,
      default: () => ({}),
    },
    path: Array,
    cell: Boolean,
  },
  created() {
    const setFunc = (obj) => {
      if (obj) {
        for (const key in obj) {
          let propValue = obj[key];
          if (
            typeof propValue === 'string' &&
            propValue.startsWith('{{') &&
            propValue.endsWith('}}')
          ) {
            this.propFunc[key] = new Function(
              'model',
              'extra',
              'row',
              'return ' + propValue.replace('{{', '').replace('}}', '')
            );
          }
        }
      }
    };
    setFunc(this.field.props);
    setFunc({ required: this.field.required });
    setFunc(this.field.extra);
  },
  data() {
    return {
      propFunc: {},
    };
  },

  computed: {
    display() {
      return this.field.display != undefined ? this.field.display : this.DiFormContext.display;
    },
    rules() {
      let rules = this.field.rules || [];

      if (this._required && !this.display) {
        let ruleRequired = rules.find((t) => t.required);
        if (!ruleRequired) {
          rules.push({ required: true, message: `${this.field.label}为必填项` });
        }
      }
      return rules;
    },
    value: {
      get() {
        return get(this.DiFormContext.model, this.path);
      },
      set(v) {
        set(this.DiFormContext.model, this.path, v);

        this.field.hooks?.afterChange &&
          this.field.hooks.afterChange({
            context: this.DiFormContext,
            value: v,
            row: this.row,
          });
      },
    },
    row() {
      if (this.path.length == 1) {
        return {};
      }
      return get(this.DiFormContext.model, this.path.slice(0, this.path.length - 1));
    },
    displayValue() {
      if (this.field.displayProp) {
        const paths = this.path.slice();
        paths[paths.length - 1] = this.field.displayProp;

        return get(this.DiFormContext.model, paths);
      }
      return undefined;
    },
    _props() {
      let funcKeys = Object.keys(this.propFunc);
      if (funcKeys === 0) {
        return this.field.props;
      }
      let props = this.field.props ? { ...this.field.props } : {};
      funcKeys.forEach((key) => {
        props[key] = this.propFunc[key](
          this.DiFormContext.model,
          this.DiFormContext.extra,
          this.row
        );
      });
      return props;
    },
    _extra() {
      let funcKeys = Object.keys(this.propFunc);
      if (funcKeys === 0) {
        return this.field.extra;
      }
      let extra = this.field.extra ? { ...this.field.extra } : {};
      funcKeys.forEach((key) => {
        extra[key] = this.propFunc[key](
          this.DiFormContext.model,
          this.DiFormContext.extra,
          this.row
        );
      });
      return extra;
    },
    _required() {
      return !this.display
        ? this.propFunc.required
          ? this.propFunc.required(this.DiFormContext.model, this.DiFormContext.extra, this.row)
          : this.field.required
        : false;
    },
  },
  inject: ['DiFormContext'],
  methods: {
    changeObj(v) {
      this.field.hooks?.changeObj &&
        this.field.hooks?.changeObj({ context: this.DiFormContext, obj: v, row: this.row });
    },
  },

  render() {
    const { field, $style, DiFormContext, rules, _props, _extra } = this;

    if (field.type === 'layout') {
      let Widget = DiFormContext.getWidget(field, 'div');

      return <Widget {..._props} class={$style.layoutItem} />;
    }
    let Widget = DiFormContext.getWidget(field);

    return (
      <div
        class={[
          $style.item,
          this.cell && $style.cell,
          _extra.hidden && $style.hidden,
          this.display && $style.display,
        ]}
        style={field.style}
      >
        <FormItem
          name={this.path}
          label={_extra.hideLabel ? '' : field.label}
          required={this._required}
          rules={rules}
          wrapperCol={
            field.style?.width == '100%' && ['textarea', '', 'input'].indexOf(field.widget) == -1
              ? { span: 24 }
              : undefined
          }
        >
          <Widget
            row={this.row}
            v-model:value={this.value}
            {..._props}
            field={field}
            displayValue={this.displayValue}
            display={this.display}
            onChangeObj={this.changeObj}
            path={this.path}
          />
        </FormItem>
      </div>
    );
  },
};
</script>

<style module lang="scss">
.item,
.layoutItem {
  display: inline-block;
  box-sizing: border-box;
  padding: 0 var(--form-gap);
  vertical-align: top;

  :global(div.ant-select.ant-select-in-form-item) {
    width: 100% !important;
  }
  :global(div.ant-picker) {
    width: 100%;
  }
  :global(div.ant-checkbox-disabled + span) {
    color: var(--text-light-gray);
  }
}

.item {
  width: var(--form-item-width);

  &.display {
    margin-bottom: 16px;
  }
}

.layoutItem {
  display: block;
  padding: 0 var(--form-gap);
}
.cell {
  width: 100%;
  padding: 0;
  :global {
    .ant-form-item-label {
      display: none !important;
    }
    div.ant-form-item {
      margin-bottom: 0;
    }
    div.ant-input-number {
      width: 100%;
    }
  }
  &.display {
    margin-bottom: 0;
  }
}
.hidden {
  display: none;
}
</style>
